package com.example.japinhands

import android.util.Log
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.japinhands.data.DeformAdj
import com.example.japinhands.data.DeformVerb
import com.example.japinhands.data.Sentence
import com.example.japinhands.data.Word
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

//@HiltViewModel
class JapViewModel : ViewModel() {
    private val TAG = "JapViewModel"

    private var _wordTypeChoice = MutableLiveData<Int>()

    val wordTypeChoice: LiveData<Int>
        get() = _wordTypeChoice

    private var _deformVerb = MutableLiveData<DeformVerb>()

    val deformVerbLiveData: LiveData<DeformVerb>
        get() = _deformVerb

    private var _deformAdj = MutableLiveData<DeformAdj>()

    val deformAdjLiveData: LiveData<DeformAdj>
        get() = _deformAdj

    private var _sentence = MutableLiveData<Sentence>()

    val sentenceLiveData: LiveData<Sentence>
        get() = _sentence

    private var _word = MutableLiveData<Word>()

    val wordToInsert: LiveData<Word>
        get() = _word

//    private var _wordsLiveData = MutableLiveData<List<Word>>()

//    val wordsLiveData: LiveData<List<Word>>
//        get() = _wordsLiveData

    val wordsUI = mutableStateListOf<Word>()
    var allowSubmit by mutableStateOf(true)


    private var deformVerbId = -1L

    private var deformAdjId = -1L

//    interface OnGetAllWordsListener {
//        fun onGetAllWords(words: Array<Word>)
//    }

    fun insertSentence(sentence: Sentence) {}

    //    fun insertDeformVerb(deformVerb: DeformVerb) = verbDao.insertDeformVerb(deformVerb)
//    fun insertDeformAdj(deformAdj: DeformAdj) = adjDao.insertDeformAdj(deformAdj)
//    fun insertWord(word: Word) = wordDao.insertWord(word)
    fun getAllSentences(onGetSentence: (List<Sentence>?) -> Unit) {
        JapRepository.getAllSentences {
            onGetSentence.invoke(it)
        }
    }
//    fun setOnAndGetAllWords(onGetAllWordsListener: OnGetAllWordsListener) {
//        thread {
//            val words = wordDao.getAllWords()
//            onGetAllWordsListener.onGetAllWords(words)
//        }
//    }

//    fun setOnGetListenerAndGetAllWords(listener: OnGetAllWordsListener) {
////        thread {
////            val words = wordDao.getAllWords()
////            listener.invoke(words)
////        }
//        viewModelScope.launch {
//            val words = withContext(Dispatchers.IO) {
//                wordDao.getAllWords()
//            }
//            listener.invoke(words)
//        }
//    }

    fun getAllWords() {
        JapRepository.getAllWords { words ->
//            _wordsLiveData.value = it.toList()
            words?.let { wordsUI.addAll(it) }
//            wordsUI.forEach { word ->
//                JapRepository.querySentenceById(word.sentenceKey) {
//                    word.sentenceContent = it?.content ?: ""
//                }
//            }
//            Log.d(TAG, "get all words: ${wordsLiveData.value}")
        }
//        viewModelScope.launch {
//            JapRepository.getAllWords().collect {
//                wordsUI.addAll(it)
//            }
//        }
//        _wordsLiveData.value = JapRepository.getAllWords()
    }

    fun queryWord(id: Long, onGetWord: (Word?) -> Unit) {
        JapRepository.queryWordById(id) { word ->
//            JapRepository.querySentenceById(word?.sentenceKey ?: -1L) {
//                word?.sentenceContent = it?.content ?: ""
//                onGetWord.invoke(word)
//            }

            onGetWord.invoke(word)
        }
    }

    fun queryDeformById(
        adjId: Long,
        verbId: Long,
        onGetVerb: (DeformVerb?) -> Unit,
        onGetAdj: (DeformAdj?) -> Unit
    ) {
        viewModelScope.launch {
            val da = JapRepository.queryDeformAdj(adjId)
            val dv = JapRepository.queryDeformVerb(verbId)
            withContext(Dispatchers.Main) {
                onGetAdj.invoke(da)
                onGetVerb.invoke(dv)
            }
        }
    }

    fun updateWord(id: Long, verbId: Long, adjId: Long) {
        wordToInsert.value?.let {
            it.id = id
            it.deformVerb = verbId
            it.deformAdj = adjId
            JapRepository.updateWord(it)
        }
    }

    fun updateDeformVerb(id: Long) {
        deformVerbLiveData.value?.let {
            it.id = id
            JapRepository.updateDeformVerb(it)
        }
    }

    fun updateDeformAdj(id: Long) {
        deformAdjLiveData.value?.let {
            it.id = id
            JapRepository.updateDeformAdj(it)
        }
    }



    fun clearWords() = wordsUI.clear()

    fun getAllDeformAdj() = JapRepository.getAllDeformAdj()
//    fun querySentenceById(id: Long) = sentenceDao.querySentenceById(id)

//    fun setOnQueryListenerAndQuerySentenceById(id: Long, listener: OnQuerySentenceListener) {
//        thread {
//            val sentence: Sentence? = sentenceDao.querySentenceById(id)
//            if (sentence != null) listener.invoke(sentence)
//        }
//    }

    fun deleteAll() = JapRepository.deleteAll()

    fun saveWordTypeChoice(type: Int) {
        _wordTypeChoice.value = type
        _word.value?.type = type
        Log.d(TAG, "Save word type choice: ${wordTypeChoice.value}")
    }

    fun saveDeformVerb(dv: DeformVerb, onSaveSuccess: () -> Unit) {
        _deformVerb.value = dv
        onSaveSuccess.invoke()
        Log.d(TAG, "Save deform verb: ${deformVerbLiveData.value?.deform1}")
    }

    fun saveDeformAdj(da: DeformAdj, onSaveSuccess: () -> Unit) {
        _deformAdj.value = da
        onSaveSuccess.invoke()
        Log.d(TAG, "Save deform adj: ${deformAdjLiveData.value?.deform1}")
    }

    fun saveSentence(s: Sentence) {
        _sentence.value = s
        Log.d(TAG, "Save sentence: ${sentenceLiveData.value.toString()}")
    }

    fun saveWord(w: Word, onSaveSuccess: () -> Unit) {
        _word.value = w
        onSaveSuccess.invoke()
        Log.d(TAG, "Save word: ${wordToInsert.value.toString()}")
    }

    fun insertDeformVerb(): Long {
        return if (deformVerbLiveData.value != null) {
            deformVerbId = JapRepository.insertDeformVerb(deformVerbLiveData.value!!)
            deformVerbId
        } else {
            Log.d(TAG, "Fail to insert deform verb, null")
            -1L
        }
    }
    fun insertDeformAdj(): Long {
        return if (deformAdjLiveData.value != null) {
            deformAdjId = JapRepository.insertDeformAdj(deformAdjLiveData.value!!)
            deformAdjId
        } else {
            Log.d(TAG, "Fail to insert deform adj, null")
            -1L
        }
    }

    fun insertSentence() {
        if (sentenceLiveData.value != null) {
            _word.value?.sentenceKey = JapRepository.insertSentence(sentenceLiveData.value!!)
            Log.d(TAG, "Insert sentence, id: ${_word.value?.sentenceKey}")
        } else {
            Log.d(TAG, "Fail to insert sentence, null")
        }
    }

    fun insertWord(): Long {
        if (deformVerbId != -1L && deformAdjId == -1L) { // 保存动词
            _word.value?.deformVerb = deformVerbId
            deformVerbId = -1L
        } else if (deformVerbId == -1L && deformAdjId != -1L) { // 保存形容词
            _word.value?.deformAdj = deformAdjId
            deformAdjId = -1L
        } else {
            Log.d(TAG, "Other case, deformAdjId: $deformAdjId and deformVerbId: $deformVerbId")
            deformAdjId = -1L
            deformVerbId = -1L
        }
        var id = -1L
        if (wordToInsert.value != null) {
            Log.d(TAG, "Before insert word, type: ${wordToInsert.value?.type}")
            id = JapRepository.insertWord(wordToInsert.value!!)
            Log.d(TAG, "After insert word: ${wordToInsert.value}")
        } else {
            Log.d(TAG, "Fail to insert word, null")
        }
        return id
    }

}

